/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "libzlang_crypto.h"

typedef int func_RSA_encrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding);
typedef int func_RSA_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding);

static int rsa_Encrypt( struct ZlangRuntime *rt , struct ZlangDirectProperty_rsakey *rsakey_direct_prop , int32_t key_size , func_RSA_encrypt *pfunc_RSA_encrypt , char *dec , int32_t dec_len , int32_t padding_type , int32_t padding_len , struct ZlangObject *out )
{
	int32_t			prepare_len ;
	char			**enc = NULL ;
	int32_t			*enc_len = NULL ;
	char			*o_dec = NULL ;
	char			*o_enc = NULL ;
	int32_t			offset ;
	int32_t			block_size ;
	char			*in = NULL ;
	int32_t			in_len ;
	int32_t			out_len ;
	
	CallRuntimeFunction_string_Clear( rt , out );
	prepare_len = ((dec_len-1)/key_size+1)*key_size + key_size ;
	CallRuntimeFunction_string_PrepareBuffer( rt , out , prepare_len );
	CallRuntimeFunction_string_GetDirectPropertiesPtr( rt , out , & enc , NULL , & enc_len );
	
	o_dec = dec ;
	o_enc = (*enc) ;
	block_size = key_size - padding_len ;
	in = (char *)malloc( block_size ) ;
	if( in == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "alloc failed , errno[%d]" , errno );
		return -1;
	}
	for( offset = 0 ; offset < dec_len ; offset += block_size )
	{
		memset( in , 0x00 , block_size );
		if( offset + block_size < dec_len )
		{
			in_len = block_size ;
		}
		else
		{
			in_len = dec_len - offset ;
		}
		memcpy( in , o_dec , in_len );
		
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "dec block [%"PRIi32"/%"PRIi32"]bytes :" , in_len , block_size )
		TEST_RUNTIME_DEBUG_THEN_PRINT_HEXSTR( rt , in , block_size )
		
		out_len = pfunc_RSA_encrypt( block_size , (unsigned char *)in , (unsigned char *)o_enc , rsakey_direct_prop->rsa , padding_type ) ;
		if( out_len == -1 )
		{
			unsigned long	err_code ;
			char		err_msg[ 256 ] = "" ;
			err_code = ERR_get_error() ;
			ERR_error_string( err_code , err_msg );
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "pfunc_RSA_encrypt failed[%d] , openssl error[%lu][%s]" , out_len , err_code , err_msg );
			free( in );
			return -11;
		}
		
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "enc block [%"PRIi32"]bytes :" , out_len )
		TEST_RUNTIME_DEBUG_THEN_PRINT_HEXSTR( rt , o_enc , out_len )
		
		o_dec += in_len ;
		o_enc += out_len ;
	}
	(*enc_len) = o_enc - (*enc) ;
	
	free( in );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_rsa_PublicKeyEncrypt_rsakey_string_int;
int ZlangInvokeFunction_rsa_PublicKeyEncrypt_rsakey_string_int( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*in2 = GetInputParameterInLocalObjectStack(rt,2) ;
	struct ZlangObject			*in3 = GetInputParameterInLocalObjectStack(rt,3) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	int32_t					key_size ;
	struct ZlangDirectProperty_rsakey	*rsakey_direct_prop = NULL ;
	char					*dec = NULL ;
	int32_t					dec_len ;
	int32_t					padding_type ;
	int32_t					padding_len ;
	int					nret = 0 ;
	
	rsakey_direct_prop = GetObjectDirectProperty(in1) ;
	if( rsakey_direct_prop->has_pubkey == TRUE )
	{
		key_size = RSA_size( rsakey_direct_prop->rsa ) ;
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "rsakey hasn't public key" );
		UnreferObject( rt , out1 );
		return 0;
	}
	
	CallRuntimeFunction_string_GetStringValue( rt , in2 , & dec , & dec_len );
	if( dec == NULL || dec_len < 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "dec or dec_len invalid" );
		UnreferObject( rt , out1 );
		return 0;
	}
	else if( dec_len == 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "dec_len[%"PRIi32"]" , dec_len );
		return 0;
	}
	
	CallRuntimeFunction_int_GetIntValue( rt , in3 , & padding_type );
	if( padding_type == CRYPTO_NO_PADDING )
	{
		padding_len = 0 ;
	}
	else if( padding_type == CRYPTO_PKCS1_PADDING )
	{
		padding_len = 11 ;
	}
	else if( padding_type == CRYPTO_PKCS1_OAEP_PADDING )
	{
		padding_len = 42 ;
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "padding[%"PRIi32"] invalid" , padding_type );
		UnreferObject( rt , out1 );
		return 0;
	}
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "padding_type[%"PRIi32"] padding_len[%"PRIi32"]" , padding_type , padding_len );
	
 	nret = rsa_Encrypt( rt , rsakey_direct_prop , key_size , RSA_public_encrypt , dec , dec_len , padding_type , padding_len , out1 ) ;
	if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "rsa_Encrypt failed[%d]" , nret );
		UnreferObject( rt , out1 );
		return 0;
	}
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_rsa_PrivateKeyEncrypt_rsakey_string_int;
int ZlangInvokeFunction_rsa_PrivateKeyEncrypt_rsakey_string_int( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*in2 = GetInputParameterInLocalObjectStack(rt,2) ;
	struct ZlangObject			*in3 = GetInputParameterInLocalObjectStack(rt,3) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	int32_t					key_size ;
	struct ZlangDirectProperty_rsakey	*rsakey_direct_prop = NULL ;
	char					*dec = NULL ;
	int32_t					dec_len ;
	int32_t					padding_type ;
	int32_t					padding_len ;
	int					nret = 0 ;
	
	rsakey_direct_prop = GetObjectDirectProperty(in1) ;
	if( rsakey_direct_prop->has_prikey == TRUE )
	{
		key_size = RSA_size( rsakey_direct_prop->rsa ) ;
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "rsakey hasn't private key" );
		UnreferObject( rt , out1 );
		return 0;
	}
	
	CallRuntimeFunction_string_GetStringValue( rt , in2 , & dec , & dec_len );
	if( dec == NULL || dec_len < 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "dec or dec_len invalid" );
		UnreferObject( rt , out1 );
		return 0;
	}
	else if( dec_len == 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "dec_len[%"PRIi32"]" , dec_len );
		return 0;
	}
	
	CallRuntimeFunction_int_GetIntValue( rt , in3 , & padding_type );
	if( padding_type == CRYPTO_NO_PADDING )
	{
		padding_len = 0 ;
	}
	else if( padding_type == CRYPTO_PKCS1_PADDING )
	{
		padding_len = 11 ;
	}
	else if( padding_type == CRYPTO_PKCS1_OAEP_PADDING )
	{
		padding_len = 42 ;
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "padding[%"PRIi32"] invalid" , padding_type );
		UnreferObject( rt , out1 );
		return 0;
	}
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "padding_type[%"PRIi32"] padding_len[%"PRIi32"]" , padding_type , padding_len );
	
 	nret = rsa_Encrypt( rt , rsakey_direct_prop , key_size , RSA_private_encrypt , dec , dec_len , padding_type , padding_len , out1 ) ;
	if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "rsa_Encrypt failed[%d]" , nret );
		UnreferObject( rt , out1 );
		return 0;
	}
	
	return 0;
}

static int rsa_Decrypt( struct ZlangRuntime *rt , struct ZlangDirectProperty_rsakey *rsakey_direct_prop , int32_t key_size , func_RSA_decrypt *pfunc_RSA_decrypt , char *enc , int32_t enc_len , int32_t padding_type , int32_t padding_len , struct ZlangObject *out )
{
	int32_t			prepare_len ;
	char			**dec = NULL ;
	int32_t			*dec_len = NULL ;
	char			*o_enc = NULL ;
	char			*o_dec = NULL ;
	int32_t			offset ;
	char			*in = NULL ;
	int32_t			in_len ;
	int32_t			out_len ;
	
	CallRuntimeFunction_string_Clear( rt , out );
	prepare_len = ((enc_len-1)/key_size+1)*key_size + key_size ;
	CallRuntimeFunction_string_PrepareBuffer( rt , out , prepare_len );
	CallRuntimeFunction_string_GetDirectPropertiesPtr( rt , out , & dec , NULL , & dec_len );
	
	o_enc = enc ;
	o_dec = (*dec) ;
	in = (char *)malloc( key_size ) ;
	if( in == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "alloc failed , errno[%d]" , errno );
		return -1;
	}
	for( offset = 0 ; offset < enc_len ; offset += key_size )
	{
		memset( in , 0x00 , key_size );
		if( offset + key_size < enc_len )
		{
			in_len = key_size ;
		}
		else
		{
			in_len = enc_len - offset ;
		}
		memcpy( in , o_enc , in_len );
		
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "enc block [%"PRIi32"/%"PRIi32"]bytes :" , in_len , key_size )
		TEST_RUNTIME_DEBUG_THEN_PRINT_HEXSTR( rt , in , key_size )
		
		out_len = pfunc_RSA_decrypt( key_size , (unsigned char *)in , (unsigned char *)o_dec , rsakey_direct_prop->rsa , padding_type ) ;
		if( out_len == -1 )
		{
			unsigned long	err_code ;
			char		err_msg[ 256 ] = "" ;
			err_code = ERR_get_error() ;
			ERR_error_string( err_code , err_msg );
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "pfunc_RSA_decrypt failed[%d] , openssl error[%lu][%s]" , out_len , err_code , err_msg );
			free( in );
			return -11;
		}
		
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "dec block [%"PRIi32"]bytes :" , out_len )
		TEST_RUNTIME_DEBUG_THEN_PRINT_HEXSTR( rt , o_dec , out_len )
		
		o_enc += in_len ;
		o_dec += out_len ;
	}
	(*dec_len) = o_dec - (*dec) ;
	
	free( in );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_rsa_PublicKeyDecrypt_rsakey_string_int;
int ZlangInvokeFunction_rsa_PublicKeyDecrypt_rsakey_string_int( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*in2 = GetInputParameterInLocalObjectStack(rt,2) ;
	struct ZlangObject			*in3 = GetInputParameterInLocalObjectStack(rt,3) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	int32_t					key_size ;
	struct ZlangDirectProperty_rsakey	*rsakey_direct_prop = NULL ;
	char					*enc = NULL ;
	int32_t					enc_len ;
	int32_t					padding_type ;
	int32_t					padding_len ;
	int					nret = 0 ;
	
	rsakey_direct_prop = GetObjectDirectProperty(in1) ;
	if( rsakey_direct_prop->has_pubkey == TRUE )
	{
		key_size = RSA_size( rsakey_direct_prop->rsa ) ;
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "rsakey hasn't public key" );
		UnreferObject( rt , out1 );
		return 0;
	}
	
	CallRuntimeFunction_string_GetStringValue( rt , in2 , & enc , & enc_len );
	if( enc == NULL || enc_len < 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "enc or enc_len invalid" );
		UnreferObject( rt , out1 );
		return 0;
	}
	else if( enc_len == 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "enc_len[%"PRIi32"]" , enc_len );
		return 0;
	}
	
	CallRuntimeFunction_int_GetIntValue( rt , in3 , & padding_type );
	if( padding_type == CRYPTO_NO_PADDING )
	{
		padding_len = 0 ;
	}
	else if( padding_type == CRYPTO_PKCS1_PADDING )
	{
		padding_len = 11 ;
	}
	else if( padding_type == CRYPTO_PKCS1_OAEP_PADDING )
	{
		padding_len = 42 ;
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "padding[%"PRIi32"] invalid" , padding_type );
		UnreferObject( rt , out1 );
		return 0;
	}
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "padding_type[%"PRIi32"] padding_len[%"PRIi32"]" , padding_type , padding_len );
	
 	nret = rsa_Decrypt( rt , rsakey_direct_prop , key_size , RSA_public_decrypt , enc , enc_len , padding_type , padding_len , out1 ) ;
	if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "rsa_Decrypt failed[%d]" , nret );
		UnreferObject( rt , out1 );
		return 0;
	}
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_rsa_PrivateKeyDecrypt_rsakey_string_int;
int ZlangInvokeFunction_rsa_PrivateKeyDecrypt_rsakey_string_int( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*in2 = GetInputParameterInLocalObjectStack(rt,2) ;
	struct ZlangObject			*in3 = GetInputParameterInLocalObjectStack(rt,3) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	int32_t					key_size ;
	struct ZlangDirectProperty_rsakey	*rsakey_direct_prop = NULL ;
	char					*enc = NULL ;
	int32_t					enc_len ;
	int32_t					padding_type ;
	int32_t					padding_len ;
	int					nret = 0 ;
	
	rsakey_direct_prop = GetObjectDirectProperty(in1) ;
	if( rsakey_direct_prop->has_prikey == TRUE )
	{
		key_size = RSA_size( rsakey_direct_prop->rsa ) ;
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "rsakey hasn't private key" );
		UnreferObject( rt , out1 );
		return 0;
	}
	
	CallRuntimeFunction_string_GetStringValue( rt , in2 , & enc , & enc_len );
	if( enc == NULL || enc_len < 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "enc or enc_len invalid" );
		UnreferObject( rt , out1 );
		return 0;
	}
	else if( enc_len == 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "enc_len[%"PRIi32"]" , enc_len );
		return 0;
	}
	
	CallRuntimeFunction_int_GetIntValue( rt , in3 , & padding_type );
	if( padding_type == CRYPTO_NO_PADDING )
	{
		padding_len = 0 ;
	}
	else if( padding_type == CRYPTO_PKCS1_PADDING )
	{
		padding_len = 11 ;
	}
	else if( padding_type == CRYPTO_PKCS1_OAEP_PADDING )
	{
		padding_len = 42 ;
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "padding[%"PRIi32"] invalid" , padding_type );
		UnreferObject( rt , out1 );
		return 0;
	}
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "padding_type[%"PRIi32"] padding_len[%"PRIi32"]" , padding_type , padding_len );
	
 	nret = rsa_Decrypt( rt , rsakey_direct_prop , key_size , RSA_private_decrypt , enc , enc_len , padding_type , padding_len , out1 ) ;
	if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "rsa_Decrypt failed[%d]" , nret );
		UnreferObject( rt , out1 );
		return 0;
	}
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_rsa_Sign_int_string_rsakey;
int ZlangInvokeFunction_rsa_Sign_int_string_rsakey( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*in2 = GetInputParameterInLocalObjectStack(rt,2) ;
	struct ZlangObject			*in3 = GetInputParameterInLocalObjectStack(rt,3) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	int					nid ;
	char					*data = NULL ;
	int32_t					data_len ;
	char					**data_sign = NULL ;
	int32_t					*data_sign_len = NULL ;
	struct ZlangDirectProperty_rsakey	*rsakey_direct_prop = NULL ;
	EVP_MD_CTX				*md_ctx = NULL ;
	EVP_PKEY				*pkey = NULL ;
	int32_t					prepare_len ;
	unsigned int				len ;
	int					nret = 0 ;
	
	CallRuntimeFunction_int_GetIntValue( rt , in1 , & nid );
	
	CallRuntimeFunction_string_GetStringValue( rt , in2 , & data , & data_len );
	if( data == NULL || data_len < 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "data or data_len invalid" );
		UnreferObject( rt , out1 );
		return 0;
	}
	else if( data_len == 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "data_len[%"PRIi32"]" , data_len );
		return 0;
	}
	
	rsakey_direct_prop = GetObjectDirectProperty(in3) ;
	if( rsakey_direct_prop->has_prikey == TRUE )
	{
		;
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "rsakey hasn't private key" );
		UnreferObject( rt , out1 );
		return 0;
	}
	
	md_ctx = EVP_MD_CTX_new() ;
	if( md_ctx == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "EVP_MD_CTX_new failed" );
		UnreferObject( rt , out1 );
		return 0;
	}
	
	pkey = EVP_PKEY_new() ;
	if( pkey == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "EVP_MD_CTX_new failed" );
		UnreferObject( rt , out1 );
		EVP_MD_CTX_free( md_ctx );
		return 0;
	}
	
	nret = EVP_PKEY_set1_RSA( pkey , rsakey_direct_prop->rsa ) ;
	if( nret != 1 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "EVP_PKEY_set1_RSA failed" );
		UnreferObject( rt , out1 );
		EVP_MD_CTX_free( md_ctx );
		EVP_PKEY_free( pkey );
		return 0;
	}
	
	nret = EVP_SignInit_ex( md_ctx , EVP_get_digestbynid(nid) , NULL ) ;
	if( nret != 1 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "EVP_SignInit_ex failed" );
		UnreferObject( rt , out1 );
		EVP_MD_CTX_free( md_ctx );
		EVP_PKEY_free( pkey );
		return 0;
	}
	
	nret = EVP_SignUpdate( md_ctx , data , data_len ) ;
	if( nret != 1 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "EVP_SignUpdate failed" );
		UnreferObject( rt , out1 );
		EVP_MD_CTX_free( md_ctx );
		EVP_PKEY_free( pkey );
		return 0;
	}
	
	CallRuntimeFunction_string_Clear( rt , out1 );
	prepare_len = RSA_size( rsakey_direct_prop->rsa ) ;
	CallRuntimeFunction_string_PrepareBuffer( rt , out1 , prepare_len );
	CallRuntimeFunction_string_GetDirectPropertiesPtr( rt , out1 , & data_sign , NULL , & data_sign_len );
	
	nret = EVP_SignFinal( md_ctx , (unsigned char *)(*data_sign) , & len , pkey ) ;
	if( nret != 1 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "EVP_SignFinal failed" );
		UnreferObject( rt , out1 );
		EVP_MD_CTX_free( md_ctx );
		EVP_PKEY_free( pkey );
		return 0;
	}
	(*data_sign_len) = len ;
	
	EVP_MD_CTX_free( md_ctx );
	EVP_PKEY_free( pkey );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_rsa_Verify_int_string_string_rsakey;
int ZlangInvokeFunction_rsa_Verify_int_string_string_rsakey( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*in2 = GetInputParameterInLocalObjectStack(rt,2) ;
	struct ZlangObject			*in3 = GetInputParameterInLocalObjectStack(rt,3) ;
	struct ZlangObject			*in4 = GetInputParameterInLocalObjectStack(rt,4) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	int					nid ;
	char					*data = NULL ;
	int32_t					data_len ;
	char					*data_sign = NULL ;
	int32_t					data_sign_len ;
	struct ZlangDirectProperty_rsakey	*rsakey_direct_prop = NULL ;
	EVP_MD_CTX				*md_ctx = NULL ;
	EVP_PKEY				*pkey = NULL ;
	int					nret = 0 ;
	
	CallRuntimeFunction_int_GetIntValue( rt , in1 , & nid );
	
	CallRuntimeFunction_string_GetStringValue( rt , in2 , & data , & data_len );
	if( data == NULL || data_len < 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "data or data_len invalid" );
		UnreferObject( rt , out1 );
		return 0;
	}
	else if( data_len == 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "data_len[%"PRIi32"]" , data_len );
		return 0;
	}
	
	CallRuntimeFunction_string_GetStringValue( rt , in3 , & data_sign , & data_sign_len );
	if( data_sign == NULL || data_sign_len < 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "sign_data or sign_data_len invalid" );
		UnreferObject( rt , out1 );
		return 0;
	}
	else if( data_sign_len == 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "data_sign_len[%"PRIi32"]" , data_sign_len );
		return 0;
	}
	
	rsakey_direct_prop = GetObjectDirectProperty(in4) ;
	if( rsakey_direct_prop->has_pubkey == TRUE )
	{
		;
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "rsakey hasn't private key" );
		UnreferObject( rt , out1 );
		return 0;
	}
	
	md_ctx = EVP_MD_CTX_new() ;
	if( md_ctx == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "EVP_MD_CTX_new failed" );
		UnreferObject( rt , out1 );
		return 0;
	}
	
	pkey = EVP_PKEY_new() ;
	if( pkey == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "EVP_MD_CTX_new failed" );
		UnreferObject( rt , out1 );
		EVP_MD_CTX_free( md_ctx );
		return 0;
	}
	
	nret = EVP_PKEY_set1_RSA( pkey , rsakey_direct_prop->rsa ) ;
	if( nret != 1 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "EVP_PKEY_set1_RSA failed" );
		UnreferObject( rt , out1 );
		EVP_MD_CTX_free( md_ctx );
		EVP_PKEY_free( pkey );
		return 0;
	}
	
	nret = EVP_VerifyInit_ex( md_ctx , EVP_get_digestbynid(nid) , NULL ) ;
	if( nret != 1 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "EVP_VerifyInit_ex failed" );
		UnreferObject( rt , out1 );
		EVP_MD_CTX_free( md_ctx );
		EVP_PKEY_free( pkey );
		return 0;
	}
	
	nret = EVP_VerifyUpdate( md_ctx , data , data_len ) ;
	if( nret != 1 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "EVP_VerifyUpdate failed" );
		UnreferObject( rt , out1 );
		EVP_MD_CTX_free( md_ctx );
		EVP_PKEY_free( pkey );
		return 0;
	}
	
	nret = EVP_VerifyFinal( md_ctx , (unsigned char *)data_sign , data_sign_len , pkey ) ;
	if( nret != 1 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "EVP_VerifyFinal failed" );
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		EVP_MD_CTX_free( md_ctx );
		EVP_PKEY_free( pkey );
		return 0;
	}
	CallRuntimeFunction_bool_SetBoolValue( rt , out1 , TRUE );
	
	EVP_MD_CTX_free( md_ctx );
	EVP_PKEY_free( pkey );
	
	return 0;
}

ZlangCreateDirectPropertyFunction ZlangCreateDirectProperty_rsa;
void *ZlangCreateDirectProperty_rsa( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_rsa	*rsa_direct_prop = NULL ;
	
	rsa_direct_prop = (struct ZlangDirectProperty_rsa *)ZLMALLOC( sizeof(struct ZlangDirectProperty_rsa) ) ;
	if( rsa_direct_prop == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for entity" )
		return NULL;
	}
	memset( rsa_direct_prop , 0x00 , sizeof(struct ZlangDirectProperty_rsa) );
	
	return rsa_direct_prop;
}

ZlangDestroyDirectPropertyFunction ZlangDestroyDirectProperty_rsa;
void ZlangDestroyDirectProperty_rsa( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_rsa	*rsa_direct_prop = GetObjectDirectProperty(obj) ;
	
	ZLFREE( rsa_direct_prop );
	
	return;
}

ZlangSummarizeDirectPropertySizeFunction ZlangSummarizeDirectPropertySize_rsa;
void ZlangSummarizeDirectPropertySize_rsa( struct ZlangRuntime *rt , struct ZlangObject *obj , size_t *summarized_obj_size , size_t *summarized_direct_prop_size )
{
	SUMMARIZE_SIZE( summarized_direct_prop_size , sizeof(struct ZlangDirectProperty_rsa) )
	return;
}

static struct ZlangDirectFunctions direct_funcs_rsa =
	{
		ZLANG_OBJECT_rsa , /* char *ancestor_name */
		
		ZlangCreateDirectProperty_rsa , /* ZlangCreateDirectPropertyFunction *create_entity_func */
		ZlangDestroyDirectProperty_rsa , /* ZlangDestroyDirectPropertyFunction *destroy_entity_func */
		
		NULL , /* ZlangFromCharPtrFunction *from_char_ptr_func */
		NULL , /* ZlangToStringFunction *to_string_func */
		NULL , /* ZlangFromDataPtrFunction *from_data_ptr_func */
		NULL , /* ZlangGetDataPtrFunction *get_data_ptr_func */
		
		NULL , /* ZlangOperatorFunction *oper_PLUS_func */
		NULL , /* ZlangOperatorFunction *oper_MINUS_func */
		NULL , /* ZlangOperatorFunction *oper_MUL_func */
		NULL , /* ZlangOperatorFunction *oper_DIV_func */
		NULL , /* ZlangOperatorFunction *oper_MOD_func */
		
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_NEGATIVE_func */
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_NOT_func */
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_BIT_REVERSE_func */
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_PLUS_PLUS_func */
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_MINUS_MINUS_func */
		
		NULL , /* ZlangCompareFunction *comp_EGUAL_func */
		NULL , /* ZlangCompareFunction *comp_NOTEGUAL_func */
		NULL , /* ZlangCompareFunction *comp_LT_func */
		NULL , /* ZlangCompareFunction *comp_LE_func */
		NULL , /* ZlangCompareFunction *comp_GT_func */
		NULL , /* ZlangCompareFunction *comp_GE_func */
		
		NULL , /* ZlangLogicFunction *logic_AND_func */
		NULL , /* ZlangLogicFunction *logic_OR_func */
		
		NULL , /* ZlangLogicFunction *bit_AND_func */
		NULL , /* ZlangLogicFunction *bit_XOR_func */
		NULL , /* ZlangLogicFunction *bit_OR_func */
		NULL , /* ZlangLogicFunction *bit_MOVELEFT_func */
		NULL , /* ZlangLogicFunction *bit_MOVERIGHT_func */
		
		ZlangSummarizeDirectPropertySize_rsa , /* ZlangSummarizeDirectPropertySizeFunction *summarize_direct_prop_size_func */
	} ;

ZlangImportObjectFunction ZlangImportObject_rsa;
struct ZlangObject *ZlangImportObject_rsa( struct ZlangRuntime *rt )
{
	struct ZlangObject	*obj = NULL ;
	struct ZlangFunction	*func = NULL ;
	int			nret = 0 ;
	
	nret = ImportObject( rt , & obj , ZLANG_OBJECT_rsa , & direct_funcs_rsa , sizeof(struct ZlangDirectFunctions) , NULL ) ;
	if( nret )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_LINK_FUNC_TO_ENTITY , "import object to global objects heap" )
		return NULL;
	}
	
	/* rsa.PublicKeyEncrypt(rsakey,string,int) */
	func = AddFunctionAndParametersInObject( rt , obj , "PublicKeyEncrypt" , "PublicKeyEncrypt(rsakey,string,int)" , ZlangInvokeFunction_rsa_PublicKeyEncrypt_rsakey_string_int , ZLANG_OBJECT_string , ZLANG_OBJECT_rsakey,NULL , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_int,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* rsa.PrivateKeyEncrypt(rsakey,string,int) */
	func = AddFunctionAndParametersInObject( rt , obj , "PrivateKeyEncrypt" , "PrivateKeyEncrypt(rsakey,string,int)" , ZlangInvokeFunction_rsa_PrivateKeyEncrypt_rsakey_string_int , ZLANG_OBJECT_string , ZLANG_OBJECT_rsakey,NULL , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_int,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* rsa.PublicKeyDecrypt(rsakey,string,int) */
	func = AddFunctionAndParametersInObject( rt , obj , "PublicKeyDecrypt" , "PublicKeyDecrypt(rsakey,string,int)" , ZlangInvokeFunction_rsa_PublicKeyDecrypt_rsakey_string_int , ZLANG_OBJECT_string , ZLANG_OBJECT_rsakey,NULL , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_int,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* rsa.PrivateKeyDecrypt(rsakey,string,int) */
	func = AddFunctionAndParametersInObject( rt , obj , "PrivateKeyDecrypt" , "PrivateKeyDecrypt(rsakey,string,int)" , ZlangInvokeFunction_rsa_PrivateKeyDecrypt_rsakey_string_int , ZLANG_OBJECT_string , ZLANG_OBJECT_rsakey,NULL , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_int,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* rsa.Sign(int,string,rsakey) */
	func = AddFunctionAndParametersInObject( rt , obj , "Sign" , "Sign(int,string,rsakey)" , ZlangInvokeFunction_rsa_Sign_int_string_rsakey , ZLANG_OBJECT_string , ZLANG_OBJECT_int,NULL , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_rsakey,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* rsa.Verify(int,string,string,rsakey) */
	func = AddFunctionAndParametersInObject( rt , obj , "Verify" , "Verify(int,string,string,rsakey)" , ZlangInvokeFunction_rsa_Verify_int_string_string_rsakey , ZLANG_OBJECT_bool , ZLANG_OBJECT_int,NULL , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_rsakey,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	return obj ;
}

